{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "<center>\n",
    "<img src=\"https://github.com/Yorko/mlcourse.ai/blob/master/img/ods_stickers.jpg?raw=true\" />\n",
    "    \n",
    "<p style=\"font-size:30px;font-weight:bold;text-align:center\">  [mlcourse.ai](https://mlcourse.ai) - Open Machine Learning Course <p/>\n",
    "<br/>\n",
    "\n",
    "<center>\n",
    "Auteur: [Egor Polusmak](https://www.linkedin.com/in/egor-polusmak/). Traduit et édité par [Yury Kashnitsky](https://yorko.github.io), [Yuanyuan Pao](https://www.linkedin.com/in/yuanyuanpao/) et [Ousmane Cissé](https://www.linkedin.com/in/ousmane-cisse/).  \n",
    "Ce matériel est soumis aux termes et conditions de la licence [Creative Commons CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/). L'utilisation gratuite est autorisée à des fins non commerciales."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "<p style=\"font-size:35px;font-weight:bold;text-align:center\">  Topic 2. Analyse visuelle des données en Python <p/>\n",
    "<br>\n",
    "\n",
    "<p style=\"font-size:25px;font-weight:bold;text-align:center\">  Part 1. Visualisation: des distributions simples à la réduction de dimension <p/>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Dans le domaine du Machine Learning, la *visualisation des données* ne consiste pas seulement à créer des graphiques sophistiqués pour les rapports; il est largement utilisé dans le travail quotidien pour toutes les phases d'un projet.\n",
    "\n",
    "Pour commencer, l'exploration visuelle des données est la première chose que l'on a tendance à faire lors d'une nouvelle tâche. Nous effectuons des vérifications et des analyses préliminaires à l'aide de graphiques et de tableaux pour résumer les données et laisser de côté les détails moins importants. Il est beaucoup plus pratique pour nous, humains, de saisir les principaux points de cette façon qu'en lisant de nombreuses lignes de données brutes. Il est étonnant de voir combien d'informations peuvent être obtenues à partir de graphiques apparemment simples créés avec les outils de visualisation disponibles.\n",
    "\n",
    "Ensuite, lorsque nous analysons les performances d'un modèle ou rapportons des résultats, nous utilisons également souvent des graphiques et des images. Parfois, pour interpréter un modèle complexe, nous devons projeter des espaces de grande dimension sur des figures 2D ou 3D plus intelligibles visuellement.\n",
    "\n",
    "Dans l'ensemble, la visualisation est un moyen relativement rapide d'apprendre quelque chose de nouveau sur vos données. Ainsi, il est essentiel d'apprendre ses techniques les plus utiles et de les intégrer à votre boîte à outils ML quotidienne.\n",
    "\n",
    "Dans cet article, nous allons acquérir une expérience pratique de l'exploration visuelle des données à l'aide de bibliothèques populaires telles que `pandas`,` matplotlib` et `seaborn`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "toc": true
   },
   "source": [
    "<h1>Article outline<span class=\"tocSkip\"></span></h1>\n",
    "<div class=\"toc\"><ul class=\"toc-item\"><li><ul class=\"toc-item\"><li><span><a href=\"#Article-outline\" data-toc-modified-id=\"Article-outline-0.1\">Article outline</a></span></li></ul></li><li><span><a href=\"#1.-Jeu-de-données\" data-toc-modified-id=\"1.-Jeu-de-données-1\">1. Jeu de données</a></span></li><li><span><a href=\"#2.-Visualisation-univariée\" data-toc-modified-id=\"2.-Visualisation-univariée-2\">2. Visualisation univariée</a></span><ul class=\"toc-item\"><li><ul class=\"toc-item\"><li><span><a href=\"#2.1-Caractéristiques-quantitatives\" data-toc-modified-id=\"2.1-Caractéristiques-quantitatives-2.0.1\">2.1 Caractéristiques quantitatives</a></span><ul class=\"toc-item\"><li><span><a href=\"#Histogrammes-et-diagrammes-de-densité\" data-toc-modified-id=\"Histogrammes-et-diagrammes-de-densité-2.0.1.1\">Histogrammes et diagrammes de densité</a></span></li><li><span><a href=\"#Box-plot-(Boîte-à-moustaches)\" data-toc-modified-id=\"Box-plot-(Boîte-à-moustaches)-2.0.1.2\">Box plot (Boîte à moustaches)</a></span></li><li><span><a href=\"#Diagramme-en-violon-(Violin-plot)\" data-toc-modified-id=\"Diagramme-en-violon-(Violin-plot)-2.0.1.3\">Diagramme en violon (Violin plot)</a></span></li><li><span><a href=\"#describe()\" data-toc-modified-id=\"describe()-2.0.1.4\">describe()</a></span></li></ul></li><li><span><a href=\"#2.2-Caractéristiques-catégorielles-et-binaires\" data-toc-modified-id=\"2.2-Caractéristiques-catégorielles-et-binaires-2.0.2\">2.2 Caractéristiques catégorielles et binaires</a></span><ul class=\"toc-item\"><li><span><a href=\"#Tableau-des-fréquences\" data-toc-modified-id=\"Tableau-des-fréquences-2.0.2.1\">Tableau des fréquences</a></span></li><li><span><a href=\"#Graphique-en-barres-(Bar-plot)\" data-toc-modified-id=\"Graphique-en-barres-(Bar-plot)-2.0.2.2\">Graphique en barres (Bar plot)</a></span></li></ul></li></ul></li></ul></li><li><span><a href=\"#3.-Visualisation-multivariée\" data-toc-modified-id=\"3.-Visualisation-multivariée-3\">3. Visualisation multivariée</a></span><ul class=\"toc-item\"><li><ul class=\"toc-item\"><li><span><a href=\"#3.1-Quantitatif-vs-Quantitatif\" data-toc-modified-id=\"3.1-Quantitatif-vs-Quantitatif-3.0.1\">3.1 Quantitatif vs Quantitatif</a></span><ul class=\"toc-item\"><li><span><a href=\"#Matrice-de-corrélation\" data-toc-modified-id=\"Matrice-de-corrélation-3.0.1.1\">Matrice de corrélation</a></span></li><li><span><a href=\"#Nuage-de-points-/-Diagramme-de-dispersion-(Scatter-plot)\" data-toc-modified-id=\"Nuage-de-points-/-Diagramme-de-dispersion-(Scatter-plot)-3.0.1.2\">Nuage de points / Diagramme de dispersion (Scatter plot)</a></span></li><li><span><a href=\"#Matrice-de-nuage-de-points-(Scatterplot-matrix)\" data-toc-modified-id=\"Matrice-de-nuage-de-points-(Scatterplot-matrix)-3.0.1.3\">Matrice de nuage de points (Scatterplot matrix)</a></span></li></ul></li><li><span><a href=\"#3.2-Quantitatif-vs-catégorique\" data-toc-modified-id=\"3.2-Quantitatif-vs-catégorique-3.0.2\">3.2 Quantitatif vs catégorique</a></span></li><li><span><a href=\"#3.3-Catégorielle-vs-catégorielle\" data-toc-modified-id=\"3.3-Catégorielle-vs-catégorielle-3.0.3\">3.3 Catégorielle vs catégorielle</a></span><ul class=\"toc-item\"><li><span><a href=\"#Tableau-de-contingence\" data-toc-modified-id=\"Tableau-de-contingence-3.0.3.1\">Tableau de contingence</a></span></li></ul></li></ul></li></ul></li><li><span><a href=\"#4.-Visualisations-de-l'ensemble-des-données\" data-toc-modified-id=\"4.-Visualisations-de-l'ensemble-des-données-4\">4. Visualisations de l'ensemble des données</a></span><ul class=\"toc-item\"><li><ul class=\"toc-item\"><li><span><a href=\"#4.1-Une-approche-naïve\" data-toc-modified-id=\"4.1-Une-approche-naïve-4.0.1\">4.1 Une approche naïve</a></span></li><li><span><a href=\"#4.2-Réduction-de-la-dimensionnalité\" data-toc-modified-id=\"4.2-Réduction-de-la-dimensionnalité-4.0.2\">4.2 Réduction de la dimensionnalité</a></span></li><li><span><a href=\"#4.3-t-SNE\" data-toc-modified-id=\"4.3-t-SNE-4.0.3\">4.3 t-SNE</a></span></li></ul></li></ul></li><li><span><a href=\"#5.-Mission-d'entraînement\" data-toc-modified-id=\"5.-Mission-d'entraînement-5\">5. Mission d'entraînement</a></span></li><li><span><a href=\"#6.-Ressources-utiles\" data-toc-modified-id=\"6.-Ressources-utiles-6\">6. Ressources utiles</a></span></li></ul></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "## 1. Jeu de données\n",
    "\n",
    "Avant d'arriver aux données, initialisons notre environnement:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T11:12:10.720219Z",
     "start_time": "2020-01-11T11:12:10.677032Z"
    }
   },
   "outputs": [],
   "source": [
    "# Matplotlib forms basis for visualization in Python\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "# We will use the Seaborn library\n",
    "import seaborn as sns\n",
    "\n",
    "sns.set()\n",
    "\n",
    "# Graphics in SVG format are more sharp and legible\n",
    "# %config InlineBackend.figure_format = 'svg'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Dans le premier article, nous avons examiné les données sur le taux de désabonnement des clients pour un opérateur de télécommunications. Nous allons recharger le même ensemble de données dans un `DataFrame`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T11:12:16.211202Z",
     "start_time": "2020-01-11T11:12:15.203212Z"
    }
   },
   "outputs": [],
   "source": [
    "df = pd.read_csv(\n",
    "    \"https://raw.githubusercontent.com/oussou-dev/mlcourse.ai/master/data/telecom_churn.csv\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Pour vous familiariser avec nos données, regardons les 5 premières entrées en utilisant `head ()`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T11:12:18.033053Z",
     "start_time": "2020-01-11T11:12:17.915597Z"
    }
   },
   "outputs": [],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Voici la description de nos variables :\n",
    "\n",
    "|  Name  | Description | Value Type | Statistical Type |\n",
    "|---         |---       |---     |---\n",
    "| **State** | State abbreviation (like KS = Kansas) | String | Categorical |\n",
    "| **Account length** | How long the client has been with the company | Numerical | Quantitative |\n",
    "| **Area code** | Phone number prefix | Numerical | Categorical |\n",
    "| **International plan** | International plan (on/off) | String, \"Yes\"/\"No\" | Categorical/Binary |\n",
    "| **Voice mail plan** | Voicemail (on/off) | String, \"Yes\"/\"No\" | Categorical/Binary |\n",
    "| **Number vmail messages** | Number of voicemail messages | Numerical | Quantitative |\n",
    "| **Total day minutes** |  Total duration of daytime calls | Numerical | Quantitative |\n",
    "| **Total day calls** | Total number of daytime calls  | Numerical | Quantitative |\n",
    "| **Total day charge** | Total charge for daytime services | Numerical | Quantitative |\n",
    "| **Total eve minutes** | Total duration of evening calls | Numerical | Quantitative |\n",
    "| **Total eve calls** | Total number of evening calls | Numerical | Quantitative |\n",
    "| **Total eve charge** | Total charge for evening services | Numerical | Quantitative |\n",
    "| **Total night minutes** | Total duration of nighttime calls | Numerical | Quantitative |\n",
    "| **Total night calls** | Total number of nighttime calls | Numerical | Quantitative |\n",
    "| **Total night charge** | Total charge for nighttime services | Numerical | Quantitative |\n",
    "| **Total intl minutes** | Total duration of international calls  | Numerical | Quantitative |\n",
    "| **Total intl calls** | Total number of international calls | Numerical | Quantitative |\n",
    "| **Total intl charge** | Total charge for international calls | Numerical | Quantitative |\n",
    "| **Customer service calls** | Number of calls to customer service | Numerical | Categorical/Ordinal |\n",
    "\n",
    "La dernière colonne de données, **Churn**, est notre variable cible. Il est binaire: *True* indique que la société a finalement perdu ce client, et *False* indique que le client a été conservé. Plus tard, nous construirons des modèles qui prédisent cette variable en fonction des variables restantes. C'est pourquoi nous l'appelons une *cible*."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "## 2. Visualisation univariée\n",
    "\n",
    "L’analyse *univariée* examine une entité à la fois. Lorsque nous analysons une entité de manière indépendante, nous sommes généralement principalement intéressés par la *distribution de ses valeurs* et ignorons les autres entités de l'ensemble de données.\n",
    "\n",
    "Ci-dessous, nous considérerons différents types statistiques d'entités et les outils correspondants pour leur analyse visuelle individuelle.\n",
    "\n",
    "#### 2.1 Caractéristiques quantitatives\n",
    "\n",
    "*Les caractéristiques quantitatives* prennent des valeurs numériques ordonnées. Ces valeurs peuvent être *discrètes*, comme des entiers, ou *continues*, comme des nombres réels, et expriment généralement un compte ou une mesure.\n",
    "\n",
    "##### Histogrammes et diagrammes de densité\n",
    "\n",
    "La façon la plus simple d'examiner la distribution d'une variable numérique est de tracer son *histogramme* à l'aide de la méthode de `DataFrame` [`hist()`](https://pandas.pydata.org /pandas-docs/stable/generated/pandas.DataFrame.hist.html)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T10:34:27.109305Z",
     "start_time": "2020-01-11T10:34:24.078904Z"
    }
   },
   "outputs": [],
   "source": [
    "features = [\"Total day minutes\", \"Total intl calls\"]\n",
    "df[features].hist(figsize=(10, 4));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Un histogramme regroupe les valeurs dans des *cases* de plage de valeurs égales. La forme de l'histogramme peut contenir des indices sur le type de distribution sous-jacent: gaussien, exponentiel, etc. Vous pouvez également repérer toute asymétrie dans sa forme lorsque la distribution est presque régulière mais présente quelques anomalies. La connaissance de la distribution des valeurs de fonction devient importante lorsque vous utilisez des méthodes de Machine Learning qui supposent un type particulier (le plus souvent gaussien).\n",
    "\n",
    "Dans le graphique ci-dessus, nous voyons que la variable *Total day minutes* est normalement distribuée, tandis que *Total intl calls* est bien asymétrique à droite (sa queue est plus longue à droite).\n",
    "\n",
    "Il existe également un autre moyen, souvent plus clair, de saisir la distribution: *diagrammes de densité* ou, plus officiellement, *diagrammes de densité de noyau*. Ils peuvent être considérés comme une version [lissée](https://en.wikipedia.org/wiki/Kernel_smoother) de l'histogramme. Leur principal avantage sur ces derniers est qu'ils ne dépendent pas de la taille des \"_bins_\". Créons des tracés de densité pour les deux mêmes variables:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T10:34:34.347065Z",
     "start_time": "2020-01-11T10:34:29.183944Z"
    }
   },
   "outputs": [],
   "source": [
    "df[features].plot(\n",
    "    kind=\"density\", subplots=True, layout=(1, 2), sharex=False, figsize=(10, 4)\n",
    ");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Il est également possible de tracer une distribution des observations avec la méthode [`distplot()`](https://seaborn.pydata.org/generated/seaborn.distplot.html) de de `seaborn`. Par exemple, regardons la distribution de *Total des minutes de jour*. Par défaut, le tracé affiche à la fois l'histogramme avec [l'estimation de la densité du noyau](https://en.wikipedia.org/wiki/Kernel _estimation de la densité_) (KDE) en haut."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T10:34:36.619014Z",
     "start_time": "2020-01-11T10:34:34.357615Z"
    }
   },
   "outputs": [],
   "source": [
    "sns.distplot(df[\"Total intl calls\"]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "La hauteur des barres d'histogramme ici est normée et montre la densité plutôt que le nombre d'exemples dans chaque case.\n",
    "\n",
    "##### Box plot (Boîte à moustaches)\n",
    "\n",
    "Un autre type de visualisation utile est un *box plot*. `seaborn` fait un excellent travail ici:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T10:34:37.923178Z",
     "start_time": "2020-01-11T10:34:36.630845Z"
    }
   },
   "outputs": [],
   "source": [
    "sns.boxplot(x=\"Total intl calls\", data=df);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Voyons comment interpréter une boîte à moustaches. Ses composants sont un *box* (évidemment, c'est pourquoi on l'appelle un *box plot*), les soi-disant *moustaches*, et un certain nombre de points individuels ( *valeurs aberrantes*).\n",
    "\n",
    "L'encadré illustre à lui seul la répartition interquartile de la distribution; sa longueur est déterminée par les centiles $25th \\, (\\text{Q1})$ et $75th \\, (\\text{Q3})$. La ligne verticale à l'intérieur de la boîte marque la médiane ($50\\%$) de la distribution.\n",
    "\n",
    "Les moustaches sont les lignes s'étendant de la boîte. Ils représentent la dispersion entière des points de données, en particulier les points qui tombent dans l'intervalle $(\\text{Q1} - 1.5 \\cdot \\text{IQR}, \\text{Q3} + 1.5 \\cdot \\text{IQR})$, où $\\text{IQR} = \\text{Q3} - \\text{Q1}$ est la [écart interquartile](https://en.wikipedia.org/wiki/Interquartile_range).\n",
    "\n",
    "Les valeurs aberrantes qui se trouvent en dehors de la plage délimitée par les moustaches sont tracées individuellement sous forme de points noirs le long de l'axe central.\n",
    "\n",
    "Nous pouvons voir qu'un grand nombre d'appels internationaux est assez rare dans nos données.\n",
    "\n",
    "##### Diagramme en violon (Violin plot)\n",
    "\n",
    "Le dernier type de diagrammes de distribution que nous considérerons est un *diagramme en violon*.\n",
    "\n",
    "Regardez les chiffres ci-dessous. Sur la gauche, nous voyons l'intrigue déjà familière. À droite, il y a un *tracé de violon* avec l'estimation de la densité du noyau des deux côtés."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T17:49:00.887532Z",
     "start_time": "2019-12-22T17:48:59.601341Z"
    }
   },
   "outputs": [],
   "source": [
    "_, axes = plt.subplots(1, 2, sharey=True, figsize=(6, 4))\n",
    "sns.boxplot(data=df[\"Total intl calls\"], ax=axes[0])\n",
    "sns.violinplot(data=df[\"Total intl calls\"], ax=axes[1]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "La différence entre la boîte et les diagrammes en violon est que la première illustre certaines statistiques concernant des exemples individuels dans un ensemble de données tandis que le diagramme en violon se concentre davantage sur la distribution lissée dans son ensemble.\n",
    "\n",
    "Dans notre cas, le graphique en violon ne fournit aucune information supplémentaire sur les données car tout est clair à partir du diagramme seul.\n",
    "\n",
    "##### describe()\n",
    "\n",
    "En plus des outils graphiques, afin d'obtenir les statistiques numériques exactes de la distribution, nous pouvons utiliser la méthode [`describe ()`](https://pandas.pydata.org/pandas-docs/stable/generated/pandas .DataFrame.describe.html) d'un `DataFrame`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T17:52:59.183751Z",
     "start_time": "2019-12-22T17:52:59.062957Z"
    }
   },
   "outputs": [],
   "source": [
    "df[features].describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Sa sortie est principalement explicite. *25%*, *50%* et *75%* sont les [centiles](https://en.wikipedia.org/wiki/Percentile) correspondants ."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "#### 2.2 Caractéristiques catégorielles et binaires\n",
    "\n",
    "*Les caractéristiques catégorielles* prennent un nombre fixe de valeurs. Chacune de ces valeurs attribue une observation à un groupe correspondant, connu sous le nom de *catégorie*, qui reflète une propriété qualitative de cet exemple. Les variables *binaires* sont un cas spécial important de variables catégorielles lorsque le nombre de valeurs possibles est exactement 2. Si les valeurs d'une variable catégorielle sont ordonnées, elle est appelée *ordinale*.\n",
    "\n",
    "##### Tableau des fréquences\n",
    "\n",
    "Vérifions l'équilibre des classes dans notre ensemble de données en examinant la distribution de la variable cible: le *taux de désabonnement*. Tout d'abord, nous obtiendrons un tableau des fréquences, qui montre la fréquence de chaque valeur de la variable catégorielle. Pour cela, nous utiliserons la méthode [`value_counts()`](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.value_ count.html) :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T17:56:37.330688Z",
     "start_time": "2019-12-22T17:56:37.297222Z"
    }
   },
   "outputs": [],
   "source": [
    "df[\"Churn\"].value_counts()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Par défaut, les entrées de la sortie sont triées des valeurs les plus fréquentes aux moins fréquentes.\n",
    "\n",
    "Dans notre cas, les données ne sont pas *équilibrées*; c'est-à-dire que nos deux classes cibles, les clients fidèles et déloyaux, ne sont pas représentées également dans l'ensemble de données. Seule une petite partie des clients a annulé leur abonnement au service de télécommunications. Comme nous le verrons dans les articles suivants, ce fait peut impliquer certaines restrictions sur la mesure des performances de classification, et, à l'avenir, nous pourrions vouloir en outre pénaliser nos erreurs de modèle dans la prédiction de la classe minoritaire \"Churn\"."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "##### Graphique en barres (Bar plot)\n",
    "\n",
    "Le diagramme à barres est une représentation graphique de la table des fréquences. La façon la plus simple de le créer est d'utiliser la fonction de `seaborn`[`countplot()`](https://seaborn.pydata.org/generated/seaborn.countplot.html). Il existe une autre fonction dans «seaborn» qui est quelque peu confondue [`barplot()`](https://seaborn.pydata.org/generated/seaborn.barplot.html) et est principalement utilisée pour la représentation de certaines statistiques de base d'une variable numérique groupée par une caractéristique catégorielle.\n",
    "\n",
    "Tracons les distributions de deux variables catégorielles:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T17:59:58.397862Z",
     "start_time": "2019-12-22T17:59:56.853761Z"
    }
   },
   "outputs": [],
   "source": [
    "_, axes = plt.subplots(nrows=1, ncols=2, figsize=(12, 4))\n",
    "\n",
    "sns.countplot(x=\"Churn\", data=df, ax=axes[0])\n",
    "sns.countplot(x=\"Customer service calls\", data=df, ax=axes[1]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Bien que les histogrammes, discutés ci-dessus, et les graphiques à barres puissent sembler similaires, il existe plusieurs différences entre eux:\n",
    "1. Les histogrammes **sont les mieux adaptés pour examiner la distribution des variables numériques tandis que les graphiques à barres sont utilisés pour les caractéristiques catégorielles**.\n",
    "2. Les valeurs sur l'axe X dans l'histogramme sont numériques; un *graphique à barres* peut avoir n'importe quel type de valeurs sur l'axe X: nombres, chaînes, booléens.\n",
    "3. L'axe X de l'histogramme *est un axe de coordonnées cartésiennes* *le long duquel les valeurs ne peuvent pas être modifiées; l'ordre des* barres *n'est pas prédéfini. Néanmoins, il est utile de noter que les barres sont souvent triées par hauteur, c'est-à-dire la fréquence des valeurs. De plus, lorsque nous considérons les variables *ordinales* (comme *les appels du service client* dans nos données), les barres sont généralement classées par valeur de variable.\n",
    "\n",
    "Le graphique de gauche ci-dessus illustre clairement le déséquilibre de notre variable cible. Le graphique à barres pour les *appels du service client* à droite indique que la majorité des clients résolvent leurs problèmes en 2 à 3 appels maximum. Mais, comme nous voulons être en mesure de prédire la classe minoritaire, nous pouvons être plus intéressés par le comportement des clients les moins satisfaits. Il se pourrait bien que la queue de ce graphique à barres contienne la majeure partie de notre taux de désabonnement. Ce ne sont que des hypothèses pour l'instant, alors passons à des techniques visuelles plus intéressantes et plus puissantes."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "## 3. Visualisation multivariée\n",
    "\n",
    "Les graphiques *multivariés* nous permettent de voir les relations entre deux et plusieurs variables différentes, le tout dans une seule figure. Tout comme dans le cas des graphiques univariés, le type spécifique de visualisation dépendra des types de variables analysées.\n",
    "\n",
    "#### 3.1 Quantitatif vs Quantitatif\n",
    "\n",
    "##### Matrice de corrélation\n",
    "\n",
    "Examinons les corrélations entre les variables numériques de notre ensemble de données. Ces informations sont importantes à connaître car il existe des algorithmes d'apprentissage automatique (par exemple, régression linéaire et logistique) qui ne gèrent pas bien les variables d'entrée hautement corrélées.\n",
    "\n",
    "Tout d'abord, nous utiliserons la méthode [`corr()`](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.corr.html) sur un `DataFrame` qui calcule la corrélation entre chaque paire de caratéristiques. Ensuite, nous passons la *matrice de corrélation* résultante à [`heatmap()`](https://seaborn.pydata.org/generated/seaborn.heatmap.html) de `seaborn`, qui rend une une matrice à code couleur pour les valeurs fournies:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T18:09:17.991936Z",
     "start_time": "2019-12-22T18:09:15.5448Z"
    }
   },
   "outputs": [],
   "source": [
    "# Drop non-numerical variables\n",
    "numerical = list(\n",
    "    set(df.columns)\n",
    "    - set(\n",
    "        [\n",
    "            \"State\",\n",
    "            \"International plan\",\n",
    "            \"Voice mail plan\",\n",
    "            \"Area code\",\n",
    "            \"Churn\",\n",
    "            \"Customer service calls\",\n",
    "        ]\n",
    "    )\n",
    ")\n",
    "\n",
    "# Calculate and plot\n",
    "corr_matrix = df[numerical].corr()\n",
    "sns.heatmap(corr_matrix);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "À partir de la matrice de corrélation colorée générée ci-dessus, nous pouvons voir qu'il y a 4 variables telles que *Total day charge* qui ont été calculées directement à partir du nombre de minutes passées sur les appels téléphoniques (*Total day minutes*). Celles-ci sont appelées variables *dépendantes* et peuvent donc être omises car elles ne fournissent aucune information supplémentaire. Débarrassons-nous d'eux:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T18:10:43.02118Z",
     "start_time": "2019-12-22T18:10:43.008373Z"
    }
   },
   "outputs": [],
   "source": [
    "numerical = list(\n",
    "    set(numerical)\n",
    "    - set(\n",
    "        [\n",
    "            \"Total day charge\",\n",
    "            \"Total eve charge\",\n",
    "            \"Total night charge\",\n",
    "            \"Total intl charge\",\n",
    "        ]\n",
    "    )\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "##### Nuage de points / Diagramme de dispersion (Scatter plot)\n",
    "\n",
    "Le *nuage de points* affiche les valeurs de deux variables numériques en tant que *coordonnées cartésiennes* dans l'espace 2D. Des diagrammes de dispersion en 3D sont également possibles.\n",
    "\n",
    "Essayons la fonction [`scatter()`](https://matplotlib.org/devdocs/api/ _as_ gen / matplotlib.pyplot.scatter.html) de la bibliothèque `matplotlib`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T18:12:31.84402Z",
     "start_time": "2019-12-22T18:12:27.150246Z"
    }
   },
   "outputs": [],
   "source": [
    "plt.scatter(df[\"Total day minutes\"], df[\"Total night minutes\"]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Nous obtenons une image sans intérêt de deux variables normalement distribuées. De plus, il semble que ces caractéristiques ne soient pas corrélées car la forme semblable à une ellipse est alignée avec les axes.\n",
    "\n",
    "Il existe une option légèrement plus sophistiquée pour créer un nuage de points avec la bibliothèque `seaborn`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T18:13:37.09501Z",
     "start_time": "2019-12-22T18:13:29.171737Z"
    }
   },
   "outputs": [],
   "source": [
    "sns.jointplot(x=\"Total day minutes\", y=\"Total night minutes\", data=df, kind=\"scatter\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "La fonction [`jointplot()`](https://seaborn.pydata.org/generated/seaborn.jointplot.html) trace deux histogrammes qui peuvent être utiles dans certains cas.\n",
    "\n",
    "En utilisant la même fonction, nous pouvons également obtenir une version lissée de notre distribution bivariée:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T18:14:52.120498Z",
     "start_time": "2019-12-22T18:14:36.115462Z"
    }
   },
   "outputs": [],
   "source": [
    "sns.jointplot(\n",
    "    \"Total day minutes\", \"Total night minutes\", data=df, kind=\"kde\", color=\"g\"\n",
    ");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Il s'agit essentiellement d'une version bivariée du *Kernel Density Plot* (estimation par noyau) discuté précédemment.\n",
    "\n",
    "##### Matrice de nuage de points (Scatterplot matrix)\n",
    "\n",
    "Dans certains cas, nous pouvons vouloir tracer une *matrice de nuage de points* telle que celle illustrée ci-dessous. Sa diagonale contient les distributions des variables correspondantes et les diagrammes de dispersion pour chaque paire de variables remplissent le reste de la matrice."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T18:21:02.025945Z",
     "start_time": "2019-12-22T18:19:39.531511Z"
    }
   },
   "outputs": [],
   "source": [
    "# `pairplot()` may become very slow with the SVG format\n",
    "%config InlineBackend.figure_format = 'png'\n",
    "sns.pairplot(df[numerical]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T18:21:42.168032Z",
     "start_time": "2019-12-22T18:21:42.128081Z"
    }
   },
   "outputs": [],
   "source": [
    "%config InlineBackend.figure_format = 'svg'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Parfois, une telle visualisation peut aider à tirer des conclusions sur les données; mais, dans ce cas, tout est assez clair sans surprise.\n",
    "\n",
    "#### 3.2 Quantitatif vs catégorique\n",
    "\n",
    "Dans cette section, nous allons rendre nos graphiques quantitatifs simples un peu plus excitants. Nous essaierons d'acquérir de nouvelles connaissances pour la prédiction du taux de désabonnement à partir des interactions entre les caractéristiques numériques et catégorielles.\n",
    "\n",
    "Plus précisément, voyons comment les variables d'entrée sont liées à la variable cible Churn.\n",
    "\n",
    "Auparavant, vous avez appris les nuages ​​de points. De plus, leurs points peuvent être codés par couleur ou par taille afin que les valeurs d'une troisième variable catégorielle soient également présentées dans la même figure. Nous pouvons y parvenir avec la fonction `scatter()` vue ci-dessus, mais essayons une nouvelle fonction appelée [`lmplot()`](https://seaborn.pydata.org/generated/seaborn.lmplot.html) et utilisez le paramètre «hue» pour indiquer notre caractéristique d'intérêt:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T18:24:13.549463Z",
     "start_time": "2019-12-22T18:24:08.985669Z"
    }
   },
   "outputs": [],
   "source": [
    "sns.lmplot(\n",
    "    \"Total day minutes\", \"Total night minutes\", data=df, hue=\"Churn\", fit_reg=False\n",
    ");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Il semble que notre faible proportion de clients déloyaux se penche vers le coin supérieur droit; c'est-à-dire que ces clients ont tendance à passer plus de temps au téléphone de jour comme de nuit. Mais ce n'est pas absolument clair et nous ne tirerons aucune conclusion définitive de ce tableau.\n",
    "\n",
    "Maintenant, créons des diagrammes en boîte pour visualiser les statistiques de distribution des variables numériques dans deux groupes disjoints: les clients fidèles (`Churn = False`) et ceux qui sont partis (` Churn = True`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T10:35:08.858977Z",
     "start_time": "2020-01-11T10:34:54.254577Z"
    }
   },
   "outputs": [],
   "source": [
    "# Sometimes you can analyze an ordinal variable just as numerical one\n",
    "numerical.append(\"Customer service calls\")\n",
    "\n",
    "fig, axes = plt.subplots(nrows=3, ncols=4, figsize=(10, 7))\n",
    "for idx, feat in enumerate(numerical):\n",
    "    ax = axes[int(idx / 4), idx % 4]\n",
    "    sns.boxplot(x=\"Churn\", y=feat, data=df, ax=ax)\n",
    "    ax.set_xlabel(\"\")\n",
    "    ax.set_ylabel(feat)\n",
    "fig.tight_layout();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Sur ce graphique, nous pouvons voir que la plus grande différence de distribution entre les deux groupes concerne trois variables: *Nombre total de minutes par jour*, *Appels au service client* et *Nombre de messages vmail*. Plus loin dans ce cours, nous apprendrons à déterminer l'importance des caractéristiques (feature importance) dans la classification à l'aide de *Random Forest* ou *Gradient Boosting*; là, nous verrons que les deux premières caractéristiques sont en effet très importantes pour la prédiction de l'attrition.\n",
    "\n",
    "Examinons séparément la distribution des minutes de la journée pour les clients fidèles et déloyaux. Nous allons créer des tracés de boîte et de violon pour *Total des minutes de la journée* regroupées par la variable cible."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T10:35:30.12209Z",
     "start_time": "2020-01-11T10:35:27.676621Z"
    }
   },
   "outputs": [],
   "source": [
    "_, axes = plt.subplots(1, 2, sharey=True, figsize=(10, 4))\n",
    "\n",
    "sns.boxplot(x=\"Churn\", y=\"Total day minutes\", data=df, ax=axes[0])\n",
    "sns.violinplot(x=\"Churn\", y=\"Total day minutes\", data=df, ax=axes[1]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Dans ce cas, le diagramme en violon ne fournit aucune information supplémentaire sur nos données car tout est clair à partir du seul duagramme : les clients déloyaux ont tendance à parler davantage au téléphone.\n",
    "\n",
    "**Une observation intéressante**: en moyenne, les clients qui résilient leurs contrats sont des utilisateurs plus actifs des services de communication. Ils sont peut-être mécontents des tarifs, donc une mesure possible pour éviter le taux de désabonnement pourrait être une réduction des tarifs d'appel. L'entreprise devra entreprendre une analyse économique supplémentaire pour déterminer si de telles mesures seraient bénéfiques.\n",
    "\n",
    "Lorsque nous voulons analyser une variable quantitative en deux dimensions catégorielles à la fois, il existe une fonction appropriée pour cela dans la bibliothèque `seaborn` appelée [`catplot() `](https://seaborn.pydata.org/generated/seaborn .factorplot.html). Par exemple, visualisons l'interaction entre *Total day minutes* et deux variables catégorielles dans le même graphique:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T11:12:32.786864Z",
     "start_time": "2020-01-11T11:12:32.769105Z"
    }
   },
   "outputs": [],
   "source": [
    "sns.catplot(\n",
    "    x=\"Churn\",\n",
    "    y=\"Total day minutes\",\n",
    "    col=\"Customer service calls\",\n",
    "    data=df[df[\"Customer service calls\"] < 8],\n",
    "    kind=\"box\",\n",
    "    col_wrap=4,\n",
    "    height=3,\n",
    "    aspect=0.8,\n",
    ");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "À partir de cela, nous pouvons conclure que, à partir de 4 appels, le *nombre total de minutes de jour* peut ne plus être le principal facteur de désabonnement des clients. Peut-être, en plus de notre supposition précédente sur les tarifs, il y a des clients qui ne sont pas satisfaits du service en raison d'autres problèmes, ce qui pourrait entraîner une réduction du nombre de minutes par jour consacrées aux appels.\n",
    "\n",
    "#### 3.3 Catégorielle vs catégorielle\n",
    "\n",
    "Comme nous l'avons vu plus haut dans cet article, la variable *Appels au service client* a peu de valeurs uniques et peut donc être considérée comme numérique ou ordinale. Nous avons déjà vu sa distribution avec un *count plot*. Maintenant, nous nous intéressons à la relation entre cette caractéristique ordinale et la variable cible *Churn*.\n",
    "\n",
    "Examinons la distribution du nombre d'appels au service client, en utilisant à nouveau un * count plot*. Cette fois, passons également le paramètre `hue = Churn` qui ajoute une dimension catégorielle au tracé:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T18:33:56.845839Z",
     "start_time": "2019-12-22T18:33:55.657863Z"
    }
   },
   "outputs": [],
   "source": [
    "sns.countplot(x=\"Customer service calls\", hue=\"Churn\", data=df);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "**Une observation**: le taux de désabonnement augmente significativement après 4 appels ou plus au service client.\n",
    "\n",
    "Examinons maintenant la relation entre *Churn* et les caratéristiques binaires, * International plan* et *Voice mail plan*."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T18:37:17.472204Z",
     "start_time": "2019-12-22T18:37:15.850608Z"
    }
   },
   "outputs": [],
   "source": [
    "_, axes = plt.subplots(1, 2, sharey=True, figsize=(10, 4))\n",
    "\n",
    "sns.countplot(x=\"International plan\", hue=\"Churn\", data=df, ax=axes[0])\n",
    "sns.countplot(x=\"Voice mail plan\", hue=\"Churn\", data=df, ax=axes[1]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "**Une observation**: lorsque *International Plan* est activé, le taux de désabonnement est beaucoup plus élevé; l'utilisation du plan international par le client est une caractéristique forte. Nous n'observons pas le même effet avec *Voice mail plan*.\n",
    "\n",
    "##### Tableau de contingence\n",
    "\n",
    "En plus d'utiliser des moyens graphiques pour l'analyse catégorielle, il existe un outil traditionnel de statistiques: un *tableau de contingence*, également appelé *tabulation croisée*. Il montre une distribution de fréquence multivariée de variables catégorielles sous forme de tableau. En particulier, il nous permet de voir la distribution d'une variable conditionnelle à l'autre en regardant le long d'une colonne ou d'une ligne.\n",
    "\n",
    "Essayons de voir comment *Churn* est lié à la variable catégorielle *State* en créant une tabulation croisée:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T18:40:00.003715Z",
     "start_time": "2019-12-22T18:39:59.840332Z"
    }
   },
   "outputs": [],
   "source": [
    "pd.crosstab(df[\"State\"], df[\"Churn\"]).T"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Dans le cas de *State*, le nombre de valeurs distinctes est assez élevé: 51. Nous voyons qu'il n'y a que quelques points de données disponibles pour chaque *individual state* - seulement 3 à 17 clients dans chaque *State* ont abandonné l'opérateur . Ignorons cela pendant une seconde et calculons le taux de désabonnement pour chaque *State*, en le triant de haut en bas:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-12-22T18:41:50.93737Z",
     "start_time": "2019-12-22T18:41:50.788703Z"
    }
   },
   "outputs": [],
   "source": [
    "df.groupby([\"State\"])[\"Churn\"].agg([np.mean]).sort_values(by=\"mean\", ascending=False).T"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "À première vue, il semble que le taux de désabonnement en *New Jersey* et *Californie* soit supérieur à 25% et inférieur à 6% pour Hawaï et l'Alaska. Cependant, ces conclusions sont basées sur trop peu d'exemples, et notre observation pourrait être une simple propriété de notre ensemble de données particulier. Nous pouvons le confirmer avec les hypothèses de [Matthews](https://en.wikipedia.org/wiki/Matthews_correlation_coefficient) et [Cramer](https://en.wikipedia.org/wiki/Cram%C3%A9r%27s_V), mais cela dépasserait le cadre de cet article."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "## 4. Visualisations de l'ensemble des données"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "#### 4.1 Une approche naïve\n",
    "\n",
    "Nous avons examiné différentes *facettes* de notre ensemble de données en devinant des caractéristiques intéressantes et en sélectionnant un petit nombre d'entre elles à la fois pour la visualisation. Nous n'avons traité que de deux à trois variables à la fois et avons pu facilement observer la structure et les relations dans les données. Mais que se passe-t-il si nous voulons afficher toutes les caratéristiques et être en mesure d'interpréter la visualisation résultante ?\n",
    "\n",
    "Nous pourrions utiliser `hist ()` ou créer une matrice de nuage de points avec `pairplot ()` pour que l'ensemble des données examine simultanément toutes nos caratéristiques. Mais, lorsque le nombre de caratéristiques est suffisamment élevé, ce type d'analyse visuelle devient rapidement lent et inefficace. En outre, nous serions toujours en train d'analyser nos variables par paires."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "#### 4.2 Réduction de la dimensionnalité\n",
    "\n",
    "La plupart des ensembles de données du monde réel ont de nombreuses caratéristiques, parfois des milliers. Chacun d'eux peut être considéré comme une dimension dans l'espace des points de données. Par conséquent, le plus souvent, nous traitons avec des ensembles de données de grande dimension, où la visualisation entière est assez difficile.\n",
    "\n",
    "Pour examiner un ensemble de données dans son ensemble, nous devons réduire le nombre de dimensions utilisées dans la visualisation sans perdre beaucoup d'informations sur les données. Cette tâche est appelée *réduction de la dimensionnalité* et est un exemple d'un problème *d'apprentissage non supervisé* parce que nous devons dériver de nouvelles caratéristiques de faible dimension à partir des données elles-mêmes, sans aucune entrée supervisée.\n",
    "\n",
    "L'une des méthodes de réduction de dimensionnalité bien connues est *analyse en composantes principales* (PCA), que nous étudierons plus loin dans ce cours. Sa limitation est qu'il s'agit d'un algorithme *linéaire* qui implique certaines restrictions sur les données.\n",
    "\n",
    "Il existe également de nombreuses méthodes non linéaires, appelées collectivement *Apprentissage multiple*. L'un des plus connus d'entre eux est le *t-SNE*."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "#### 4.3 t-SNE\n",
    "\n",
    "Créons une représentation [t-SNE](https://en.wikipedia.org/wiki/T-distributed _stochastique_ neighbour_embedding) des mêmes données de désabonnement que nous utilisons.\n",
    "\n",
    "Le nom de la méthode semble complexe et un peu intimidant: *it-distributed Stohastic Neighbor Embedding*. Ses calculs sont également impressionnants (nous ne nous y attarderons pas ici, mais, si vous vous sentez courageux, voici [l'article original](http://www.jmlr.org/papers/volume9/vandermaaten08a/vandermaaten08a.pdf) par Laurens van der Maaten et Geoffrey Hinton de [JMLR](http://www.jmlr.org/)). Son idée de base est simple: trouver une projection pour un espace d'entité de haute dimension sur un plan (ou un hyperplan 3D, mais c'est presque toujours 2D) de telle sorte que ces points qui étaient éloignés l'un de l'autre dans l'espace n-dimensionnel initial finiront loin dans l'avion. Ceux qui étaient à l'origine proches resteraient proches les uns des autres.\n",
    "\n",
    "Essentiellement, *l'incorporation de voisins* est une recherche d'une nouvelle représentation de données moins dimensionnelle qui préserve le voisinage d'exemples.\n",
    "\n",
    "Maintenant, faisons un peu de pratique. Tout d'abord, nous devons importer des classes supplémentaires:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T11:12:54.683355Z",
     "start_time": "2020-01-11T11:12:54.240016Z"
    }
   },
   "outputs": [],
   "source": [
    "from sklearn.manifold import TSNE\n",
    "from sklearn.preprocessing import StandardScaler"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Nous laisserons de côté les caractéristiques *State* et *Churn* et convertirons les valeurs \"Yes\"/\"No\" des caractéristiques binaires en valeurs numériques à l'aide de [`pandas.Series.map ()` ](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.map.html):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T11:12:58.127557Z",
     "start_time": "2020-01-11T11:12:58.079268Z"
    }
   },
   "outputs": [],
   "source": [
    "X = df.drop([\"Churn\", \"State\"], axis=1)\n",
    "X[\"International plan\"] = X[\"International plan\"].map({\"Yes\": 1, \"No\": 0})\n",
    "X[\"Voice mail plan\"] = X[\"Voice mail plan\"].map({\"Yes\": 1, \"No\": 0})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Nous devons également normaliser les données. Pour cela, nous allons soustraire la moyenne de chaque variable et la diviser par son écart-type. Tout cela peut être fait avec «StandardScaler»."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T11:13:01.722905Z",
     "start_time": "2020-01-11T11:13:01.693276Z"
    }
   },
   "outputs": [],
   "source": [
    "scaler = StandardScaler()\n",
    "X_scaled = scaler.fit_transform(X)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Maintenant, construisons une représentation t-SNE:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T11:18:54.732255Z",
     "start_time": "2020-01-11T11:13:07.084657Z"
    }
   },
   "outputs": [],
   "source": [
    "%%time\n",
    "tsne = TSNE(random_state=17)\n",
    "tsne_repr = tsne.fit_transform(X_scaled)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "et traçons-le:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T12:30:52.201637Z",
     "start_time": "2020-01-11T12:30:51.209473Z"
    }
   },
   "outputs": [],
   "source": [
    "plt.scatter(tsne_repr[:, 0], tsne_repr[:, 1], alpha=0.5);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Colorons cette représentation t-SNE en fonction du taux de désabonnement (bleu pour les clients fidèles et orange pour ceux qui ont désabonné)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T12:31:24.840886Z",
     "start_time": "2020-01-11T12:31:23.210278Z"
    }
   },
   "outputs": [],
   "source": [
    "plt.scatter(\n",
    "    tsne_repr[:, 0],\n",
    "    tsne_repr[:, 1],\n",
    "    c=df[\"Churn\"].map({False: \"blue\", True: \"orange\"}),\n",
    "    alpha=0.5,\n",
    ");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Nous pouvons voir que les clients qui se dont désabonnés, \n",
    "sont concentrés dans quelques zones de l'espace caractéristique de dimension inférieure.\n",
    "\n",
    "Pour mieux comprendre l'image, nous pouvons également la colorier avec les caractéristiques binaires restantes: *Plan international* et *Messagerie vocale*. Les points orange indiquent ici les instances positives pour la fonction binaire correspondante."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-01-11T12:32:10.541489Z",
     "start_time": "2020-01-11T12:32:06.421012Z"
    }
   },
   "outputs": [],
   "source": [
    "_, axes = plt.subplots(1, 2, sharey=True, figsize=(12, 5))\n",
    "\n",
    "for i, name in enumerate([\"International plan\", \"Voice mail plan\"]):\n",
    "    axes[i].scatter(\n",
    "        tsne_repr[:, 0],\n",
    "        tsne_repr[:, 1],\n",
    "        c=df[name].map({\"Yes\": \"orange\", \"No\": \"blue\"}),\n",
    "        alpha=0.5,\n",
    "    )\n",
    "    axes[i].set_title(name);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Maintenant, il est clair que, par exemple, de nombreux clients insatisfaits qui ont annulé leur abonnement sont regroupés dans un cluster représentant les personnes bénéficiant du plan international mais pas de messagerie vocale.\n",
    "\n",
    "Enfin, notons quelques inconvénients du t-SNE:\n",
    "- Haute complexité de calcul. La [mise en œuvre](http://scikit-learn.org/stable/modules/generated/sklearn.manifold.TSNE.html) dans `scikit-learn` est peu susceptible d'être réalisable dans une tâche réelle. Si vous avez un grand nombre d'échantillons, vous devriez plutôt essayer [Multicore-TSNE](https://github.com/DmitryUlyanov/Multicore-TSNE).\n",
    "- Le tracé peut changer beaucoup en fonction du \"_seed_\" aléatoire, ce qui complique l'interprétation. [Via ce lien](http://distill.pub/2016/misread-tsne/) vous trouverez un bon tutoriel sur t-SNE. En général, vous ne devriez pas tirer de conclusions de grande envergure sur la base de tels graphiques, car cela peut équivaloir à une simple supposition. Bien sûr, certains résultats dans les images t-SNE peuvent inspirer une idée et être confirmés par des recherches plus approfondies sur la ligne, mais cela ne se produit pas très souvent.\n",
    "\n",
    "Parfois, en utilisant t-SNE, vous pouvez obtenir une très bonne intuition pour les données. Ce qui suit est un bon article qui en montre un exemple pour les chiffres manuscrits: [Visualizing MNIST](https://colah.github.io/posts/2014-10-Visualizing-MNIST/).\n",
    "\n",
    "<img src='https://github.com/Yorko/mlcourse.ai/blob/master/img/tsne_mnist.png?raw=true' />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "## 5. Mission d'entraînement\n",
    "Pour vous entraîner à l'analyse visuelle des données, vous pouvez effectuer [cette mission](https://www.kaggle.com/kashnitsky/a2-demo-analyzing-cardiovascular-data) où vous analyserez les données sur les maladies cardiovasculaires."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "## 6. Ressources utiles\n",
    "- The same notebook as an interactive web-based [Kaggle Kernel](https://www.kaggle.com/kashnitsky/topic-2-visual-data-analysis-in-python)\n",
    "- [\"Plotly for interactive plots\"](https://nbviewer.jupyter.org/github/Yorko/mlcourse.ai/blob/master/jupyter_english/tutorials/plotly_tutorial_for_interactive_plots_sankovalev.ipynb) - a tutorial by Alexander Kovalev within mlcourse.ai (full list of tutorials is [here](https://mlcourse.ai/tutorials))\n",
    "- [\"Bring your plots to life with Matplotlib animations\"](https://nbviewer.jupyter.org/github/Yorko/mlcourse.ai/blob/master/jupyter_english/tutorials/bring_your_plots_to_life_with_matplotlib_animations_kyriacos_kyriacou.ipynb) - a tutorial by Kyriacos Kyriacou within mlcourse.ai\n",
    "- [\"Some details on Matplotlib\"](https://nbviewer.jupyter.org/github/Yorko/mlcourse.ai/blob/master/jupyter_english/tutorials/some_details_in_matplotlib_pisarev_ivan.ipynb) - a tutorial by Ivan Pisarev within mlcourse.ai\n",
    "- Main course [site](https://mlcourse.ai), [course repo](https://github.com/Yorko/mlcourse.ai), and YouTube [channel](https://www.youtube.com/watch?v=QKTuw4PNOsU&list=PLVlY_7IJCMJeRfZ68eVfEcu-UcN9BbwiX)\n",
    "- Medium [\"story\"](https://medium.com/open-machine-learning-course/open-machine-learning-course-topic-2-visual-data-analysis-in-python-846b989675cd) based on this notebook\n",
    "- Course materials as a [Kaggle Dataset](https://www.kaggle.com/kashnitsky/mlcourse)\n",
    "- If you read Russian: an [article](https://habrahabr.ru/company/ods/blog/323210/) on Habrahabr with ~ the same material. And a [lecture](https://youtu.be/vm63p8Od0bM) on YouTube\n",
    "- Here is the official documentation for the libraries we used: [`matplotlib`](https://matplotlib.org/contents.html), [`seaborn`](https://seaborn.pydata.org/introduction.html) and [`pandas`](https://pandas.pydata.org/pandas-docs/stable/).\n",
    "- The [gallery](http://seaborn.pydata.org/examples/index.html) of sample charts created with `seaborn` is a very good resource.\n",
    "- Also, see the [documentation](http://scikit-learn.org/stable/modules/manifold.html) on Manifold Learning in `scikit-learn`.\n",
    "- Efficient t-SNE implementation [Multicore-TSNE](https://github.com/DmitryUlyanov/Multicore-TSNE).\n",
    "- \"How to Use t-SNE Effectively\", [Distill.pub](https://distill.pub/2016/misread-tsne/)."
   ]
  }
 ],
 "metadata": {
  "hide_input": false,
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4"
  },
  "nbTranslate": {
   "displayLangs": [
    "*"
   ],
   "hotkey": "alt-t",
   "langInMainMenu": true,
   "sourceLang": "en",
   "targetLang": "fr",
   "useGoogleTranslate": true
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Article outline",
   "title_sidebar": "Contents",
   "toc_cell": true,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
